enyo.kind({
	kind: enyo.Object,
	name: "com.rextoy.CalcModel",
	
	status: 0,
	/*
		0 - Start 
		1 - Number(decimal) inputting
		2 - Wait For Next Input		
		4 - Memory/Function Return(MR/Func Button)
		5 - Error
	*/
	
	radix: 10,
	register: 0,
	operator: 0,
	/*
		1 - +
		2 - -
		3 - *
		4 - /
		9 - ^
	*/
	current: 0,
	memory: 0,
	angelMode: 0,	
	/*
		0 - Deg, 1 - Rad, 2 - Grad
	*/
	
	hasMemory: false,
	input: '',
	
	create: function(){
	},
	
	setView: function(view){
		this.view = view;		
	},
	
	updateView: function(){
		this.view.updateView();
	},
	
	setAngelMode: function(val) {
		this.angelMode = val;
	},
	
	setRadix: function(val) {
		this.register = 0;
		this.operator = 0;
		this.status = 4;
		
		this.radix = val;
		this.current = Math.round(this.current);
		try{
			this.validateResult(this.current);
		} catch(e) {
			this.status = 5;
		}
		this.view.updateView();
	},
	
	getResult: function(){
		if(this.status != 1)
			return Number(this.current.toFixed(15));
		else {
			if(this.radix==10)
				return this.input;//Note:Must return string -- otherwise if you input 0.005, it always show 0 until you input 5
			else
				return parseInt(this.input, this.radix);
		}
	},
	
	getMemory: function(){
		return Number(this.memory.toFixed(15));
	},
	
	getRegister: function(){
		return Number(this.register.toFixed(15));
	},
	
	calc: function() {
		var r;
		switch(this.operator){
			case 1:
				r = this.register + this.current;
				break;
			
			case 2:
				r = this.register - this.current;
				break;
				
			case 3:
				r = this.register * this.current;
				break;
				
			case 4:
				r = this.register / this.current;
				break;
				
			case 9:
				r = Math.pow(this.register, this.current);
		}
		if(this.radix!=10) {
			this.log('--------------' + r);
			r = Math.round(r);
			this.log('--------------' + r);
		}
		this.current = r;
		
		this.validateResult(r);
	},
	
	validateResult: function(r){
		if(isNaN(r))
			throw 'NaN';
		if(!isFinite(r))
			throw 'Inf';
		
		switch(this.radix){
			case 2:
				if(this.current > Math.pow(2,32) || this.current < -Math.pow(2,32))
					throw 'Ovf';
				break;	
			
			case 8:
				if(this.current > Math.pow(8,32) || this.current < -Math.pow(8,32))
					throw 'Ovf';
				break;
				
			case 16:
				if(this.current > Math.pow(16,32) || this.current < -Math.pow(16,32))
					throw 'Ovf';
				break;
		}		
	},
	
	inputNumber: function(val) {
		if(this.status == 5)
			return;
		//limit the length user can input
		if(this.input.length > 20)
			return;
		
		this.log('input buffer is : ' + this.input + val);
		switch(this.status) {
			case 0:
			case 4:
				this.input = '' + val;
				this.status = 1;
				break;
				
			case 1:
				this.input += val;
				break;
			
			case 2:
				this.register = this.current;
				this.input = '' + val;
				this.status = 1;
				break;
		}
		
		if(this.radix==10) {
			this.current = Number(this.input);
		} else {
			this.log('parse[' + this.input.toLowerCase() + ']of[' + this.radix + ']');
			this.current = parseInt(this.input.toLowerCase(), this.radix);
		}
		
		var allZero = true;
		for(var i = 0; i < this.input.length; i++){
			if(this.input[i] !== '0')
				allZero = false;
		}
		if(allZero)
			this.input = '0';
		if(this.input.length > 1 && this.input[0] === '0' && this.input[1] !== '.')//Remove lead zero
			this.input = this.input.substr(1);
		
		this.updateView();
	},
	
	inputDecimal: function(){
		switch(this.status){
			case 5:
				return;
				
			case 0:
			case 4:
				this.input = "0.";
				this.status = 1;
				break;
				
			case 1:
				if(this.input.indexOf('.') != -1)
					return;
				else
					this.input += '.';
				break;
				
			case 2:
				this.input = "0.";
				this.status = 1;
				break;
		}
		this.current = Number(this.input);
		this.updateView();
	},
	
	inputOperator: function(val) {
		switch(this.status)	{
			case 5:
				return;
		
			case 0:
			case 4:
				this.register = this.current;
				this.operator = val;
				this.status = 2;
				break;
				
			case 1:
				if(this.operator != 0) {
					try{
						this.calc();
					} catch (e) {
						this.status = 5;
						this.updateView();
						return;
					}
				}
				this.register = this.current;
				this.operator = val;
				this.status = 2;
				break;
				
			case 2:
				this.operator = val;
				break;
		}		
		
		this.updateView();
	},	
	
	inputEqual: function() {
		if(this.status == 5) return;
		
		if(this.status == 1 || this.status == 3 || this.status == 4){
			if(this.operator == 0)
				return;
			
			try{
				this.calc();
				this.register = 0;
				this.operator = 0;
				this.status = 0;
				this.input = this.current + '';
			} catch (e) {
				this.log(e);
				this.status = 5;
			}
			this.updateView();
		}
	},
	
	inputClear: function() {		
		this.register = 0;
		this.current = 0;
		this.operator = 0;
		this.status = 0;
		this.input = '';
		this.updateView();
	},
	
	inputBack: function() {
		if(this.status == 1){//Only valid when inputting number
			if(this.input.length <= 1) {
				this.input = '0';
				this.current = 0;
			} else {
				this.input = this.input.substr(0, this.input.length - 1);
				this.current = Number(this.input);
			}
			this.updateView();
		}
	},
	
	inputSign: function() {	
		if(this.status == 2 || this.status == 5)
			return;
		var ch = this.input[0];
		if(ch == '-') 
			this.input = this.input.substr(1);
		else
			this.input = '-' + this.input;
		this.current = Number(this.input);
		this.updateView();
	},
	
	inputPercent: function() {
		if(this.status == 2 || this.status == 5)
			return;
		
		this.current = this.current / 100;
		this.input = this.current + '';
		this.status = 4;
		this.updateView();
	},
	
	inputReciprocal: function() {
		if(this.status == 2 || this.status == 5)
			return;
		//TODO:Error handle if current = 0
		try {		
			this.current = 1 / this.current;
			this.validateResult(this.current);
			this.input = this.current + '';
			this.status = 4;
		} catch (e) {
			this.status = 5;
		}
		this.updateView();
	},
	
	inputSqrt: function() {
		if(this.status == 2 || this.status == 5)
			return;
		if(this.current >= 0){
			this.current = Math.sqrt(this.current);
			this.input = this.current + '';
			this.status = 4;
		} else {
			this.status = 5;
		}
		
		this.updateView();
	},
	
	inputCbrt: function() {
		if(this.status == 2 || this.status == 5)
			return;
		
		this.current = Math.pow(this.current, 1/3);
		this.input = this.current + '';
		this.status = 4;
		this.updateView();
	},
	
	inputFunc: function(val){
		if(this.status == 2 || this.status == 5)
			return;
		
		if(val == 'sin' || val == 'cos' || val == 'tan' || val == 'asin' || val == 'acos' || val == 'atan') {
			switch(this.angelMode) {
				case 0:
					this.current = Math.PI * this.current / 180;
					break;
				case 1://Rad, do nothing
					break;
				case 2:
					this.current = Math.PI * this.current / 200;
					break;
			}
		}
		
		if(val == 'fac') {
			if(this.current.toString().search(/^[0-9]+$/) != 0){
				this.status = 5;
				this.updateView();
				return;
			}
		}
		
		try {
			this.current = Math[val](this.current);		
			this.input = this.current + '';
			this.status = 4;
			this.validateResult(this.current);
		} catch(e) {
			this.status = 5;
		}
		this.updateView();
	},
	
	inputConst: function(val){
		if(this.status == 5)
			return;
			
		this.current = Math[val];
		this.input = this.current + '';
		this.status = 4;
		this.updateView();
	},
	
	inputMemory: function(option) {
		if(this.status == 5) return;
	
		//TODO:possible overflow error in M+/M-
		switch(option) {
			case 0://MC
				this.hasMemory = false;
				this.memory = 0;
				this.status = 2;
				break;
				
			case 1://M+
				this.memory += this.current;
				this.hasMemory = true;
				this.status = 2;
				break;
				
			case 2://M-
				this.memory -= this.current;
				this.hasMemory = true;
				this.status = 2;
				break;
				
			case 3://MR
				if(this.hasMemory) {
					this.current = this.memory;
					this.status = 4;
					this.updateView();
					return;
				}
				break;
		}
		try{
			this.validateResult(this.memory);
		} catch(e){
			this.status = 5;
		}
		
		this.updateView();
	}
});